/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.support.transform.excel;

import cn.easyplatform.contexts.Contexts;
import cn.easyplatform.contexts.WorkflowContext;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.i18n.I18N;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Nums;
import cn.easyplatform.log.LogManager;
import cn.easyplatform.messages.vos.executor.BeginVo;
import cn.easyplatform.messages.vos.executor.ErrorVo;
import cn.easyplatform.spi.listener.event.MessageEvent;
import cn.easyplatform.support.transform.AbstractTransformer;
import cn.easyplatform.support.transform.Parameter;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.util.MessageUtils;
import org.apache.commons.io.IOUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ExcelToTableTransformer extends
        AbstractTransformer<Workbook, Map<String, List<List<FieldDo>>>> {

    private final static Logger LOG = LoggerFactory.getLogger(ExcelToTableTransformer.class);

    @Override
    public void transform(Workbook wb, Parameter parameter) {
        if (parameter != null && parameter.isProgress()) {
            CommandContext cc = Contexts.getCommandContext();
            WorkflowContext ctx = cc.getWorkflowContext();
            BeginVo bv = new BeginVo((I18N.getLabel("upload.execute.begin")));
            cc.send(new MessageEvent(ctx.getId(), bv));
            new Thread(() -> {
                Contexts.set(CommandContext.class, cc);
                LogManager.beginRequest(cc.getEnv().getId(), cc.getUser());
                try {
                    process(wb, parameter);
                } catch (Exception ex) {
                    if (LOG.isErrorEnabled())
                        LOG.error("transform", ex);
                    cc.send(new MessageEvent(ctx.getId(), new ErrorVo(MessageUtils.getMessage(ex))));
                } finally {
                    Contexts.clear();
                }
            }).start();
        } else
            process(wb, parameter);
    }

    private void process(Workbook wb, Parameter parameter) {
        try {
            String[] sheets = parameter.getSheets();
            int columnsRow = parameter.getColumnsRow();
            int size = wb.getNumberOfSheets();
            Map<String, List<List<FieldDo>>> data = new HashMap<String, List<List<FieldDo>>>();
            int count = 0;
            for (int numSheet = 0; numSheet < size; numSheet++) {
                Sheet sheet = wb.getSheetAt(numSheet);
                if (sheet != null) {
                    count++;
                    if (sheets != null) {
                        boolean match = false;
                        for (String s : sheets) {
                            if (!match) {
                                int n = Nums.toInt(s, 0);
                                if (count == n
                                        || s.equals(sheet.getSheetName())) {
                                    match = true;
                                    break;
                                }// if
                            }// if
                        }// for
                        if (!match)
                            continue;
                    }
                    int rowNums = sheet.getLastRowNum();
                    if (rowNums > 0) {
                        List<List<FieldDo>> records = new ArrayList<List<FieldDo>>();
                        Row columnRow = null;
                        if (columnsRow >= 0)
                            columnRow = sheet.getRow(columnsRow);
                        for (int rowNum = 0; rowNum <= rowNums; rowNum++) {
                            Row row = sheet.getRow(rowNum);
                            if (row != null) {
                                List<FieldDo> record = new ArrayList<FieldDo>();
                                for (int celNum = 0; celNum < row
                                        .getLastCellNum(); celNum++) {
                                    Cell cell = row.getCell(celNum);
                                    FieldDo field = null;
                                    if (cell != null)
                                        field = getValue(row.getCell(celNum));
                                    else
                                        field = new FieldDo(FieldType.VARCHAR,
                                                "");
                                    if (columnRow != null) {
                                        Object val = getValue(
                                                columnRow.getCell(celNum))
                                                .getValue();
                                        field.setName((String) val);
                                    } else
                                        field.setName(String
                                                .valueOf(celNum + 1));
                                    record.add(field);
                                }
                                records.add(record);
                            } else {
                                List<FieldDo> record = Collections.emptyList();
                                records.add(record);
                            }
                        }
                        data.put(sheet.getSheetName(), records);
                    }
                }
            }
            handler.transform(data, parameter);
        } finally {
            IOUtils.closeQuietly(wb);
            wb = null;
        }
    }

    private FieldDo getValue(Cell cell) {
        switch (cell.getCellType()) {
            case NUMERIC:// 数字类型
                if (HSSFDateUtil.isCellDateFormatted(cell)) {// 处理日期格式、时间格式
                    return new FieldDo(FieldType.DATE, cell.getDateCellValue());
                } else if (cell.getCellStyle().getDataFormat() == 14
                        | cell.getCellStyle().getDataFormat() == 31
                        || cell.getCellStyle().getDataFormat() == 57
                        || cell.getCellStyle().getDataFormat() == 58
                        || cell.getCellStyle().getDataFormat() == 20
                        || cell.getCellStyle().getDataFormat() == 32) {
                    double value = cell.getNumericCellValue();
                    Date date = org.apache.poi.ss.usermodel.DateUtil
                            .getJavaDate(value);
                    return new FieldDo(FieldType.DATE, date);
                } else {
                    return new FieldDo(FieldType.NUMERIC,
                            cell.getNumericCellValue());
                }
            case STRING:// String类型
                return new FieldDo(FieldType.VARCHAR, cell.getRichStringCellValue()
                        .toString().trim());
            case BLANK:
                return new FieldDo(FieldType.VARCHAR, "");
            case BOOLEAN:
                return new FieldDo(FieldType.BOOLEAN, cell.getBooleanCellValue());
            default:
                return new FieldDo(FieldType.VARCHAR, cell.getStringCellValue()
                        .trim());
        }
    }
}
